package my.springboot.controller;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import my.springboot.domain.primary.Dict;
import my.springboot.domain.primary.Xml111;
import my.springboot.domain.secondary.SuccessKilled;
import my.springboot.po.bo.PageBO;
import my.springboot.po.vo.VoData;
import my.springboot.service.GlobalLockService;
import my.springboot.service.KafkaService;
import my.springboot.service.MessagePushService;
import my.springboot.service.ZhihuUserService;
import my.springboot.util.DateUtils;
import my.springboot.util.ReturnUtils;
import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.TransactionMQProducer;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.common.RemotingHelper;
import org.apache.rocketmq.remoting.exception.RemotingException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;
import springfox.documentation.annotations.ApiIgnore;

import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Size;
import java.io.UnsupportedEncodingException;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 首页控制器
 * @author fengbo
 * @date 2017/9/3
 */
@Api(value = "/", tags = "首页显示模块 by fengbo")
@Controller
@Validated
@Slf4j
public class HomeController {

    @Value("${my.desc}")
    @NotEmpty
    private String desc;

    @Autowired
    private ZhihuUserService zhihuUserService;
    @Autowired
    private MessagePushService messagePushService;
    @Autowired
    private GlobalLockService globalLockService;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @ApiIgnore
    @GetMapping(value = {"/", "/index"})
    public String zhihu() {
        return "zhihu/index";
    }

    /***
     * 知乎用户统计数据
     */
    @ApiOperation(value = "知乎用户列表", notes = "知乎用户统计信息")
    @GetMapping("/data")
    @ResponseBody
    public Map<String, Object> zhihuData() {
        Map<String, Object> map = zhihuUserService.getAllPage();
        map.put("female", zhihuUserService.countBySex("female"));
        map.put("male", zhihuUserService.countBySex("male"));
        map.put("unknown", zhihuUserService.countBySex());
        return map;
    }

    /**
     * 每天第一次访问和之后的访问结果不同
     */
    @GetMapping("/redis")
    @ResponseBody
    public VoData<String> redis() {
        int uid = 1;
        String key = String.format("MSG:RECOMMEND:%s", uid);
        // 用户授权后，每天第一次访问时推荐一款商品
        long expireTime = DateUtils.getEndTimeForDay().getTime() - System.currentTimeMillis();
        // 今天24点减去当前时间
        Boolean isOk = redisTemplate.opsForValue().setIfAbsent(key, 1, expireTime, TimeUnit.MILLISECONDS);
        if(Boolean.TRUE.equals(isOk)) {
            return ReturnUtils.success("first");
        }
        return ReturnUtils.success("not first");
    }

    @GetMapping("/redis/lock")
    @ResponseBody
    public VoData redisLock(Integer id) {
        String key = "test";
        String value = UUID.randomUUID().toString();
        try {
            if (globalLockService.lock(key, value, 30, TimeUnit.MINUTES)) {
                System.out.println("start lock id = " + id);
                try {
                    Thread.sleep(1000 * 60);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("end lock id = " + id);
            }
            System.out.println("over id = " + id);
        } finally {
            boolean unlock = globalLockService.unlock(key, value);
            System.out.println("unlock id = " + id + " ret = " + unlock);
        }
        return ReturnUtils.success();
    }

    @GetMapping("/async")
    @ResponseBody
    public VoData async(String name) {
        messagePushService.testAsync(name);
        return ReturnUtils.success();
    }

    /**
     * 注解数据校验实现
     */
    @PostMapping("/valid")
    @ResponseBody
    public VoData valid(@RequestBody @Valid SuccessKilled successKilled){
        return ReturnUtils.success(successKilled);
    }

    @GetMapping("/prop")
    @ResponseBody
    public VoData<String> prop(@Size(min = 4) String str) {
        log.info(str);
        return ReturnUtils.success(desc);
    }

    @Autowired
    private KafkaService kafkaService;

    @GetMapping("/kafka/test")
    @ResponseBody
    public VoData kafka(PageBO bo) {
        kafkaService.sendMsg(bo);
        return ReturnUtils.success();
    }

    @Autowired
    private TransactionMQProducer producer;
    @GetMapping("/rocket/test")
    @ResponseBody
    public VoData rocket(String str) throws UnsupportedEncodingException, InterruptedException, RemotingException, MQClientException, MQBrokerException {
        Message msg = new Message("RequestTopic",
                "",
                str.getBytes(RemotingHelper.DEFAULT_CHARSET));
        Dict dict = new Dict();
        dict.setParamKey(str);
        dict.setParamValue(str);
        dict.setParentKey("msg");
        producer.sendMessageInTransaction(msg, dict);
        return ReturnUtils.success();
    }

    @PostMapping(value = "/user",
            consumes = MediaType.APPLICATION_XML_VALUE,
            produces = MediaType.APPLICATION_XML_VALUE)
    @ResponseBody
    public Xml111 create(@RequestBody Xml111 user) {
        user.setName("didispace.com : " + user.getName());
        user.setAge(user.getAge() + 100);
        return user;
    }
}
